using System;
using System.Collections;
using System.Collections.Generic;
using OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup;
using UnityEditor;
using UnityEditor.IMGUI.Controls;
using UnityEngine;
using XFABManager;

namespace XFGameFramework.ScriptableObjectSystem
{
    //internal class IconGUIContent
    //{
    //    public string projectName;
    //    public string iconName;
    //    public GUIContent content;
    //}


    public class ScriptableObjectListTree : DragableTreeView<ScriptableObjectData>
    {

        private ScriptableObjectConfigs scriptableObjectConfigs;

        private bool isContextClickItem;

        private Rect icon_rect;
        private Rect name_rect;
        private Rect id_rect;

        //private Dictionary<int, IconGUIContent> contents = new Dictionary<int, IconGUIContent>();

        private GUIStyle label_style;

        private Dictionary<int, GUIContent> displayNameContents = new Dictionary<int, GUIContent>();

        public ScriptableObjectConfigs ScriptableObjectConfigs => scriptableObjectConfigs;

#if UNITY_6000_2_OR_NEWER
        public ScriptableObjectListTree(ScriptableObjectConfigs scriptableObjectConfigs, IList<ScriptableObjectData> datas, TreeViewState<int> state)
#else
        public ScriptableObjectListTree(ScriptableObjectConfigs scriptableObjectConfigs, IList<ScriptableObjectData> datas, TreeViewState state)
#endif

            : base(scriptableObjectConfigs, datas, state)
        {
            this.scriptableObjectConfigs = scriptableObjectConfigs;
            showBorder = true;
            rowHeight = 25;
        }

#if UNITY_6000_2_OR_NEWER
        protected override void OnBuildRoot(TreeViewItem<int> root, IList<ScriptableObjectData> datas)
#else
        protected override void OnBuildRoot(TreeViewItem root, IList<ScriptableObjectData> datas)
#endif
        {
            base.OnBuildRoot(root, datas);

            foreach (var item in datas)
            {
                if (item == null) continue;

#if UNITY_6000_2_OR_NEWER
                TreeViewItem<int> child = new TreeViewItem<int>(item.id, 0, string.Format("{0}-{1}", item.config_name, item.id));
#else
                TreeViewItem child = new TreeViewItem(item.id, 0, string.Format("{0}-{1}", item.config_name, item.id));
#endif

                root.AddChild(child);
            }
        }

        protected override void RowGUI(RowGUIArgs args)
        {
            if (scriptableObjectConfigs == null) return;

            ScriptableObjectData info = scriptableObjectConfigs.GetScriptableObjectData(args.item.id);

            if (info == null) return;

            icon_rect.Set(0, args.rowRect.y, args.rowRect.height, args.rowRect.height);
            name_rect.Set(args.rowRect.height, args.rowRect.y, args.rowRect.width - args.rowRect.height - 70, args.rowRect.height);

            id_rect.Set(args.rowRect.width - 70, args.rowRect.y, 70, args.rowRect.height);
             
            GUIContent icon_content = EditorAssetTool.GetTextureGUIContent(info.icon.projectName, info.icon.iconName);
             
            EditorGUI.LabelField(icon_rect, icon_content);

            if (!displayNameContents.ContainsKey(info.id))
                displayNameContents.Add(info.id, new GUIContent());

            displayNameContents[info.id].text = GetDisplayName(info);
            displayNameContents[info.id].tooltip = info.des;

            if (label_style == null)
            {
                label_style = new GUIStyle(EditorStyles.label);
                label_style.richText = true;
            }

            EditorGUI.LabelField(name_rect, displayNameContents[info.id], label_style);

            GUI.Label(id_rect, string.Format("id:{0}", info.id), "AnimationTimelineTick");

            GUI.Box(args.rowRect, string.Empty, "CN Box");
        }

#if UNITY_6000_2_OR_NEWER
        protected override bool CanMultiSelect(TreeViewItem<int> item)
#else
        protected override bool CanMultiSelect(TreeViewItem item)
#endif

        {
            return true;
        }

        protected override void ContextClicked()
        {
            base.ContextClicked();

            if (isContextClickItem)
            {
                isContextClickItem = false;
                return;
            }

            GenericMenu menu = new GenericMenu();
            CreateScriptableObject(menu);
        }

        protected override void ContextClickedItem(int id)
        {
            base.ContextClickedItem(id);
             
            isContextClickItem = true;

            GenericMenu menu = new GenericMenu();
            menu.AddItem(new GUIContent("删除"), false, () =>
            {
                IList<int> selects = GetSelection();

                foreach (var item in selects)
                {
                    DeleteSkill(item);
                }

                AssetDatabase.SaveAssets();
                Reload();
            });

            menu.AddItem(new GUIContent("复制"), false, () =>
            {
                IList<int> selects = GetSelection();

                List<int> ids = new List<int>();

                foreach (var item in selects)
                {
                    int id = CopySkill(item);
                    if (id == -1) continue;
                    ids.Add(id);
                }

                AssetDatabase.SaveAssets();
                Reload();

                SetSelection(ids);
            });

            menu.AddSeparator(string.Empty);
            CreateScriptableObject(menu);
        }


        private void CreateScriptableObject(GenericMenu menu)
        {
            //  查找项目中所有继承自 
            List<Type> skills = GetAllSkillTypes(scriptableObjectConfigs.GetDataType());

            foreach (var item in skills)
            {
                string name = string.Format("创建配置/{0}", item.Name);
                if (!string.IsNullOrEmpty(item.Namespace))
                    name = string.Format("{0}-{1}", name, item.Namespace);

                if (item == typeof(ScriptableObjectData))
                    name = "创建配置/基础配置";

                GUIContent content = new GUIContent(name);

                menu.AddItem(content, false, () =>
                {
                    int id = ScriptableObjectConfigsController.CreateSkillConfigData(item, scriptableObjectConfigs);
                    SetSelection(new int[] { id });
                });
            }


            menu.ShowAsContext();
        }

        private void DeleteSkill(int id)
        {
            if (scriptableObjectConfigs == null) return;

            ScriptableObjectData data = scriptableObjectConfigs.GetScriptableObjectData(id);
            if (data == null) return;

            AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(data));
            scriptableObjectConfigs.configs.Remove(data);
            EditorUtility.SetDirty(scriptableObjectConfigs);
        }

        private int CopySkill(int id)
        {
            if (scriptableObjectConfigs == null) return -1;

            ScriptableObjectData data = scriptableObjectConfigs.GetScriptableObjectData(id);
            if (data == null) return -1;

            ScriptableObjectData skillConfigData = GameObject.Instantiate(data);
            int new_id = ScriptableObjectConfigsController.CreateSkillConfigData(skillConfigData, scriptableObjectConfigs);
            skillConfigData.config_name = ScriptableObjectConfigsController.GetCopyName(data.config_name, scriptableObjectConfigs);
            return new_id;
        }

        public static List<Type> GetAllSkillTypes(Type parent)
        {
            List<Type> states = new List<Type>();

            states.Add(parent);

            string[] scripts = AssetDatabase.FindAssets("t:Script");

            foreach (var item in scripts)
            {
                string path = AssetDatabase.GUIDToAssetPath(item);
                MonoScript script = AssetDatabase.LoadAssetAtPath<MonoScript>(path);

                if (script == null) continue;

                Type type = script.GetClass();

                if (type == null) continue;

                if (type.IsSubclassOf(parent))
                    states.Add(type);
            }

            return states;
        }


        protected override void RefreshDatas()
        {
            base.RefreshDatas();
            if (scriptableObjectConfigs != null)
                scriptableObjectConfigs.ClearCache();
        }

        private string GetDisplayName(ScriptableObjectData skillConfigData)
        {
            if (string.IsNullOrEmpty(skillConfigData.des))
                return skillConfigData.config_name;

            return string.Format("{0}(<color=grey>{1}</color>)", skillConfigData.config_name, skillConfigData.des.Replace("\n", string.Empty));
        }

    }
}

